package com.cal.utms.model.dealing;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import com.cal.utms.dao.dealing.DealDao;
import com.cal.utms.dao.maintenance.DealTypeDao;
import com.cal.utms.dao.maintenance.IssuerDaoImpl;
import com.cal.utms.dao.maintenance.MasterDataDaoImpl;
import com.cal.utms.dao.maintenance.NewFundDao;
import com.cal.utms.dto.dealing.RevRepoDealDto;
import com.cal.utms.entity.Deal;
import com.cal.utms.entity.DealInstrumentMap;
import com.cal.utms.entity.Dealer;
import com.cal.utms.entity.DelevaryMethod;
import com.cal.utms.entity.Fund;
import com.cal.utms.entity.Issuer;
import com.cal.utms.entity.SettlementMethod;
import com.cal.utms.util.Sequence;
import com.cal.utms.valuation.ReverseRepoCalculator;

public class RevRepoDealModel {

	public Deal creatRevRepoDeal(RevRepoDealDto revRepoDealDto) {
		Deal deal = new Deal();
		deal.setCreatedDate(new Date());
		deal.setDealType(new DealTypeDao().getDealTypeByCode("RREPO"));
		deal.setCreatedUser(revRepoDealDto.getUser());
		deal.setStatus("Initial");

		Sequence seq = new Sequence();
		String dealCode = "RR" + seq.getNextValue("DealSequence");
		deal.setDealCode(dealCode);
		List<DealInstrumentMap> dimList = new ArrayList<DealInstrumentMap>();
		deal.setDealInstrumentMaps(dimList);
		return mapDtoToDeal(revRepoDealDto, deal);
	}

	private Deal mapDtoToDeal(RevRepoDealDto revRepoDealDto, Deal deal) {
		DateFormat df = new SimpleDateFormat("dd/MM/yyyy", Locale.ENGLISH);
		NumberFormat nf = NumberFormat.getInstance();
		Date date = null;
		Number number;

		if (revRepoDealDto.getFund() != 0) {
			NewFundDao nfd = new NewFundDao();
			Fund fund = nfd.getById(revRepoDealDto.getFund());
			if (fund != null) {
				deal.setFund(fund);
			} else {
				revRepoDealDto.setSuccess(false);
				revRepoDealDto.setStatus("Invalid Fund!");
				return deal;
			}
		} else {
			revRepoDealDto.setSuccess(false);
			revRepoDealDto.setStatus("Empty Fund!");
			return deal;
		}

		if (revRepoDealDto.getIssuer() != 0) {
			IssuerDaoImpl issuerDao = new IssuerDaoImpl();
			Issuer issuer = issuerDao.getById(revRepoDealDto.getIssuer());
			if (issuer != null) {
				deal.setIssuer(issuer);
			} else {
				revRepoDealDto.setSuccess(false);
				revRepoDealDto.setStatus("Invalid Issuer!");
				return deal;
			}
		} else {
			revRepoDealDto.setSuccess(false);
			revRepoDealDto.setStatus("Empty Issuer!");
			return deal;
		}

		MasterDataDaoImpl masterDataDaoImpl = new MasterDataDaoImpl();
		if (revRepoDealDto.getSettlementCode() != 0) {
			SettlementMethod method = masterDataDaoImpl.getSettlementById(revRepoDealDto.getSettlementCode());
			if (method != null)
				deal.setSettlementMethod(method);
			else {
				revRepoDealDto.setSuccess(false);
				revRepoDealDto.setStatus("Invalid Settlement Methode!");
				return deal;
			}
		}
		if (revRepoDealDto.getDelevarymethode() != 0) {
			DelevaryMethod delevaryMethod = masterDataDaoImpl.getDelevaryMethodById(revRepoDealDto.getDelevarymethode());
			if (delevaryMethod != null)
				deal.setDelevarymethode(delevaryMethod);
			else {
				revRepoDealDto.setSuccess(false);
				revRepoDealDto.setStatus("Invalid Delevary Methode!");
				return deal;
			}
		}

		if (revRepoDealDto.getDealerCode() != 0) {
			Dealer dealer = masterDataDaoImpl.getdealerByid(revRepoDealDto.getDealerCode());
			if (dealer != null)
				deal.setDealerCode(dealer);
			else {
				revRepoDealDto.setSuccess(false);
				revRepoDealDto.setStatus("Invalid Dealer!");
				return deal;
			}
		}

		if (revRepoDealDto.getValueDate() != null) {
			try {
				date = df.parse(revRepoDealDto.getValueDate());
				deal.setValueDate(date);
			} catch (ParseException pe) {
				revRepoDealDto.setSuccess(false);
				revRepoDealDto.setStatus("Value Date Parse Error!");
				return deal;
			}
		} else {
			revRepoDealDto.setSuccess(false);
			revRepoDealDto.setStatus("Empty Value Date!");
			return deal;
		}

		if (revRepoDealDto.getMaturityDate() != null) {
			try {
				System.out.println("matDt:" + revRepoDealDto.getMaturityDate());
				date = df.parse(revRepoDealDto.getMaturityDate());
				System.out.println(date);
				deal.setMaturityDate(date);
			} catch (ParseException pe) {
				revRepoDealDto.setSuccess(false);
				revRepoDealDto.setStatus("Maturity Date Parse Error!");
				return deal;
			}
		} else {
			revRepoDealDto.setSuccess(false);
			revRepoDealDto.setStatus("Empty Value Date!");
			return deal;
		}

		if (revRepoDealDto.getPrincipleValue() != null) {
			try {
				number = nf.parse(revRepoDealDto.getPrincipleValue());
				deal.setDealValue(new BigDecimal(number.doubleValue()));
			} catch (ParseException e) {
				revRepoDealDto.setSuccess(false);
				revRepoDealDto.setStatus("Principle Value Parse Error!");
				return deal;
			}
		} else {
			revRepoDealDto.setSuccess(false);
			revRepoDealDto.setStatus("Empty Principle Value!");
			return deal;
		}

		if (revRepoDealDto.getMaturityValue() != null) {
			try {
				number = nf.parse(revRepoDealDto.getMaturityValue());
				deal.setMaturityValue(new BigDecimal(number.doubleValue()));
			} catch (ParseException e) {
				revRepoDealDto.setSuccess(false);
				revRepoDealDto.setStatus("Maturity Value Parse Error!");
				return deal;
			}
		} else {
			revRepoDealDto.setSuccess(false);
			revRepoDealDto.setStatus("Empty Maturity Value!");
			return deal;
		}

		deal.setActualRate(new BigDecimal(revRepoDealDto.getActualRate().replace("%", "")));
		deal.setDayBasis(revRepoDealDto.getDayBasis());
		deal.setWithholdingTax("No");

		if (revRepoDealDto.getParams() != null && !revRepoDealDto.getParams().trim().equals("")) {
			deal.setRolloverShortmaturity(revRepoDealDto.getParams());
		}
		return deal;
	}

	public RevRepoDealDto mapRepoToDto(Deal deal) {
		NumberFormat nf = new DecimalFormat("###,###.00");
		DateFormat df = new SimpleDateFormat("dd/MM/yyyy");
		RevRepoDealDto revRepoDealDto = new RevRepoDealDto();

		revRepoDealDto.setId(deal.getId());
		revRepoDealDto.setDealCode(deal.getDealCode());
		revRepoDealDto.setFund(deal.getFund().getId());
		revRepoDealDto.setIssuer(deal.getIssuer().getId());
		revRepoDealDto.setValueDate(df.format(deal.getValueDate()));
		revRepoDealDto.setMaturityDate(df.format(deal.getMaturityDate()));
		revRepoDealDto.setPrincipleValue(nf.format(deal.getDealValue().doubleValue()));
		revRepoDealDto.setActualRate(nf.format(deal.getActualRate()) + "%");
		revRepoDealDto.setDayBasis(deal.getDayBasis());
		revRepoDealDto.setStatus(deal.getStatus());

		if (deal.getSettlementMethod() != null)
			revRepoDealDto.setSettlementCode(deal.getSettlementMethod().getId());
		if (deal.getDelevarymethode() != null)
			revRepoDealDto.setDelevarymethode(deal.getDelevarymethode().getId());
		if (deal.getDealerCode() != null)
			revRepoDealDto.setDealerCode(deal.getDealerCode().getId());
		return revRepoDealDto;
	}

	public Deal confRevRepoDeal(RevRepoDealDto revRepoDealDto) {
		DealDao dealDao = new DealDao();
		Deal deal = dealDao.getByCode(revRepoDealDto.getDealCode());
		deal.setStatus("Confirmed");
		deal.setConfirmedUser(revRepoDealDto.getUser());
		deal.setConfirmedDate(new Date());
		return mapDtoToDeal(revRepoDealDto, deal);
	}

	public Deal updateRevRepoDeal(Deal deal, RevRepoDealDto revRepoDealDto) {
		deal.setModifiedDate(new Date());
		deal.setModifiedUser(revRepoDealDto.getUser());
		return mapDtoToDeal(revRepoDealDto, deal);
	}

	public RevRepoDealDto valuate(RevRepoDealDto revRepoDealDto) {
		DateFormat df = new SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH);
		NumberFormat nf = NumberFormat.getInstance();
		Date valueDate = null;
		Date maturityDate = null;
		Number principleValue = null;

		if (revRepoDealDto.getValueDate() == null) {
			revRepoDealDto.setStatus("Empty Value Date");
			revRepoDealDto.setSuccess(true);
			return revRepoDealDto;
		} else {
			try {
				valueDate = df.parse(revRepoDealDto.getValueDate());
			} catch (ParseException pe) {
				revRepoDealDto.setSuccess(false);
				revRepoDealDto.setStatus("Value Date Parse Error!");
				return revRepoDealDto;
			}
		}
		if (revRepoDealDto.getMaturityDate() == null) {
			revRepoDealDto.setStatus("Empty Maturity Date");
			revRepoDealDto.setSuccess(true);
			return revRepoDealDto;
		} else {
			try {
				maturityDate = df.parse(revRepoDealDto.getMaturityDate());
			} catch (ParseException pe) {
				revRepoDealDto.setSuccess(false);
				revRepoDealDto.setStatus("Maturity Date Parse Error!");
				return revRepoDealDto;
			}
		}
		if (revRepoDealDto.getPrincipleValue() == null) {
			revRepoDealDto.setSuccess(false);
			revRepoDealDto.setStatus("Empty Principle Value!");
			return revRepoDealDto;
		} else {
			try {
				principleValue = nf.parse(revRepoDealDto.getPrincipleValue());
			} catch (ParseException e) {
				revRepoDealDto.setSuccess(false);
				revRepoDealDto.setStatus("Principle Value Parse Error!");
				return revRepoDealDto;
			}
		}
		System.out.println(revRepoDealDto.getActualRate());
		System.out.println(Double.parseDouble(revRepoDealDto.getActualRate().replace("%", "")));
		if (Double.parseDouble(revRepoDealDto.getActualRate().replace("%", "")) < 0 || Double.parseDouble(revRepoDealDto.getActualRate().replace("%", "")) > 100) {
			revRepoDealDto.setSuccess(false);
			revRepoDealDto.setStatus("Invalid Actual Rate!");
			return revRepoDealDto;
		}
		ReverseRepoCalculator reverseRepoCalculator = new ReverseRepoCalculator();
		reverseRepoCalculator.valuateAllParameters(principleValue.doubleValue(), Double.parseDouble(revRepoDealDto.getActualRate().replace("%", "")), revRepoDealDto.getDayBasis(),
				valueDate, maturityDate);
		revRepoDealDto.setMaturityValue(nf.format(reverseRepoCalculator.getMaturityValue()));

		return revRepoDealDto;
	}
}
